{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "7f4e4862",
   "metadata": {},
   "outputs": [],
   "source": [
    "zidian = {\n",
    "    '<PAD>': 0,\n",
    "    '1': 1,\n",
    "    '2': 2,\n",
    "    '3': 3,\n",
    "    '4': 4,\n",
    "    '5': 5,\n",
    "    '6': 6,\n",
    "    '7': 7,\n",
    "    '8': 8,\n",
    "    '9': 9,\n",
    "    '0': 10,\n",
    "    'Jan': 11,\n",
    "    'Feb': 12,\n",
    "    'Mar': 13,\n",
    "    'Apr': 14,\n",
    "    'May': 15,\n",
    "    'Jun': 16,\n",
    "    'Jul': 17,\n",
    "    'Aug': 18,\n",
    "    'Sep': 19,\n",
    "    'Oct': 20,\n",
    "    'Nov': 21,\n",
    "    'Dec': 22,\n",
    "    '-': 23,\n",
    "    '/': 24,\n",
    "    '<SOS>': 25,\n",
    "    '<EOS>': 26,\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "652b0528",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[10,  3, 23,  1,  2, 23,  1,  7],\n",
       "         [ 7,  4, 23,  1,  1, 23,  2, 10],\n",
       "         [ 1,  4, 23,  1,  2, 23, 10,  6],\n",
       "         [ 9,  3, 23, 10,  1, 23,  1,  8],\n",
       "         [ 8,  4, 23, 10,  7, 23,  1,  5]]),\n",
       " torch.Size([100, 8]),\n",
       " tensor([[25,  1,  7, 24, 22, 24,  2, 10, 10,  3, 26],\n",
       "         [25,  2, 10, 24, 21, 24,  1,  9,  7,  4, 26],\n",
       "         [25, 10,  6, 24, 22, 24,  2, 10,  1,  4, 26],\n",
       "         [25,  1,  8, 24, 11, 24,  1,  9,  9,  3, 26],\n",
       "         [25,  1,  5, 24, 17, 24,  1,  9,  8,  4, 26]]),\n",
       " torch.Size([100, 11]))"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import numpy as np\n",
    "import datetime\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "\n",
    "class DateDataset(Dataset):\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    def __len__(self):\n",
    "        return 2000\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        #随机生成一个日期\n",
    "        date = np.random.randint(143835585, 2043835585)\n",
    "        date = datetime.datetime.fromtimestamp(date)\n",
    "\n",
    "        #格式化成两种格式\n",
    "        #05-06-15\n",
    "        #15/Jun/2005\n",
    "        date_cn = date.strftime(\"%y-%m-%d\")\n",
    "        date_en = date.strftime(\"%d/%b/%Y\")\n",
    "\n",
    "        #中文的就是简单的拿字典编码就行了\n",
    "        date_cn_code = [zidian[v] for v in date_cn]\n",
    "\n",
    "        #英文的,首先要在收尾加上标志位,然后用字典编码\n",
    "        date_en_code = []\n",
    "        date_en_code += [zidian['<SOS>']]\n",
    "        date_en_code += [zidian[v] for v in date_en[:3]]\n",
    "        date_en_code += [zidian[date_en[3:6]]]\n",
    "        date_en_code += [zidian[v] for v in date_en[6:]]\n",
    "        date_en_code += [zidian['<EOS>']]\n",
    "\n",
    "        return torch.LongTensor(date_cn_code), torch.LongTensor(date_en_code)\n",
    "\n",
    "\n",
    "dataloader = DataLoader(dataset=DateDataset(),\n",
    "                        batch_size=100,\n",
    "                        shuffle=True,\n",
    "                        drop_last=True)\n",
    "\n",
    "#遍历数据\n",
    "for i, data in enumerate(dataloader):\n",
    "    sample = data\n",
    "    break\n",
    "sample[0][:5], sample[0].shape, sample[1][:5], sample[1].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "5b4cd93c",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[ 0.1473, -0.0341,  0.1209,  0.0353,  0.0812,  0.0153, -0.1422,  0.0362,\n",
       "           0.1948,  0.1156, -0.0300,  0.0039, -0.1499,  0.1529,  0.1944, -0.0194,\n",
       "           0.0252,  0.2329, -0.0066,  0.1822, -0.0936,  0.0540,  0.2010, -0.1069,\n",
       "          -0.0065, -0.0252,  0.2074],\n",
       "         [ 0.1502,  0.0118,  0.0584,  0.0598,  0.1239, -0.0718, -0.0987,  0.1868,\n",
       "           0.2064,  0.0504,  0.0181,  0.0182, -0.0039,  0.0583,  0.1820,  0.1181,\n",
       "          -0.0599,  0.0680,  0.0413,  0.1691, -0.1661,  0.0211,  0.1889, -0.1276,\n",
       "          -0.0683, -0.0461,  0.2365]], grad_fn=<SliceBackward>),\n",
       " torch.Size([100, 10, 27]))"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class CNN(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "\n",
    "        #encoder\n",
    "        #一共27个词,编码成16维向量\n",
    "        self.encoder_embed = nn.Embedding(num_embeddings=27, embedding_dim=16)\n",
    "\n",
    "        #卷积层\n",
    "        self.encoder_conv_2 = nn.Conv2d(in_channels=1,\n",
    "                                        out_channels=16,\n",
    "                                        kernel_size=(2, 16),\n",
    "                                        padding=0)\n",
    "        self.encoder_conv_3 = nn.Conv2d(in_channels=1,\n",
    "                                        out_channels=16,\n",
    "                                        kernel_size=(3, 16),\n",
    "                                        padding=0)\n",
    "        self.encoder_conv_4 = nn.Conv2d(in_channels=1,\n",
    "                                        out_channels=16,\n",
    "                                        kernel_size=(4, 16),\n",
    "                                        padding=0)\n",
    "\n",
    "        #池化层\n",
    "        self.encoder_pool_7 = nn.MaxPool2d(kernel_size=(7, 1))\n",
    "        self.encoder_pool_6 = nn.MaxPool2d(kernel_size=(6, 1))\n",
    "        self.encoder_pool_5 = nn.MaxPool2d(kernel_size=(5, 1))\n",
    "\n",
    "        #全连接层\n",
    "        self.encoder_fc = nn.Linear(in_features=48, out_features=32)\n",
    "\n",
    "        #decoder\n",
    "        #一共27个词,编码成16维向量\n",
    "        self.decoder_embed = nn.Embedding(num_embeddings=27, embedding_dim=16)\n",
    "\n",
    "        #输入是16维向量,隐藏层是32维向量\n",
    "        self.decoder_cell = nn.LSTMCell(input_size=16, hidden_size=32)\n",
    "\n",
    "        #输入是32维向量,输出是27分类\n",
    "        self.out_fc = nn.Linear(in_features=32, out_features=27)\n",
    "\n",
    "    def encode(self, x):\n",
    "        #x编码\n",
    "        #[b,8] -> [b,8,16]\n",
    "        x = self.encoder_embed(x)\n",
    "\n",
    "        #增加一维,模拟图片的通道\n",
    "        #[b,8,16] -> [b,1,8,16]\n",
    "        x = x.unsqueeze(dim=1)\n",
    "\n",
    "        #卷积层\n",
    "        #[b,1,8,16] -> [b,16,7,1]\n",
    "        conv_2 = F.relu(self.encoder_conv_2(x))\n",
    "\n",
    "        #[b,1,8,16] -> [b,16,6,1]\n",
    "        conv_3 = F.relu(self.encoder_conv_3(x))\n",
    "\n",
    "        #[b,1,8,16] -> [b,16,5,1]\n",
    "        conv_4 = F.relu(self.encoder_conv_4(x))\n",
    "\n",
    "        #池化层\n",
    "        #[b,16,7,1] -> [b,16,1,1]\n",
    "        conv_2 = self.encoder_pool_7(conv_2)\n",
    "\n",
    "        #[b,16,6,1] -> [b,16,1,1]\n",
    "        conv_3 = self.encoder_pool_6(conv_3)\n",
    "\n",
    "        #[b,16,5,1] -> [b,16,1,1]\n",
    "        conv_4 = self.encoder_pool_5(conv_4)\n",
    "\n",
    "        #去除多余维度\n",
    "        #[b,16,1,1] -> [b,16]\n",
    "        conv_2 = conv_2.squeeze()\n",
    "        conv_3 = conv_3.squeeze()\n",
    "        conv_4 = conv_4.squeeze()\n",
    "\n",
    "        #卷积结果全部拼合在一起\n",
    "        #[b,16],[b,16],[b,16] -> [b,48]\n",
    "        h = torch.cat([conv_2, conv_3, conv_4], dim=1)\n",
    "\n",
    "        #全连接层\n",
    "        #[b,48] -> [b,32]\n",
    "        h = self.encoder_fc(h)\n",
    "\n",
    "        return h, h\n",
    "\n",
    "    def forward(self, x, y):\n",
    "\n",
    "        #编码层\n",
    "        #[b,32]\n",
    "        h, c = self.encode(x)\n",
    "\n",
    "        #丢弃y的最后一个词\n",
    "        #因为训练的时候是以y的每一个词输入,预测下一个词\n",
    "        #所以不需要最后一个词\n",
    "        #[b,11] -> [b,10]\n",
    "        y = y[:, :-1]\n",
    "\n",
    "        #y编码\n",
    "        #[b,10] -> [b,10,16]\n",
    "        y = self.decoder_embed(y)\n",
    "\n",
    "        #用cell遍历y的每一个词\n",
    "        outs = []\n",
    "        for i in range(10):\n",
    "\n",
    "            #把y的每个词依次输入循环网络\n",
    "            #第一个词的记忆是x的最后一个词的记忆\n",
    "            #往后每个词的记忆是上一个词的记忆\n",
    "            #[b,16] -> [b,32],[b,32]\n",
    "            h, c = self.decoder_cell(y[:, i], (h, c))\n",
    "\n",
    "            #把每一步的记忆输出成词\n",
    "            #[b,32] -> [b,27]\n",
    "            out = self.out_fc(h)\n",
    "            outs.append(out)\n",
    "\n",
    "        #把所有的输出词组合成一句话\n",
    "        outs = torch.stack(outs, dim=0)\n",
    "        #[10,b,27] -> #[b,10,27]\n",
    "        outs = outs.permute(1, 0, 2)\n",
    "\n",
    "        return outs\n",
    "\n",
    "\n",
    "model = CNN()\n",
    "\n",
    "out = model(sample[0], sample[1])\n",
    "out[0, :2], out.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "20f541cd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 1.9974745512008667\n",
      "10 0.5927864909172058\n",
      "20 0.24106037616729736\n",
      "30 0.09821534156799316\n",
      "40 0.046583663672208786\n",
      "50 0.025665022432804108\n",
      "60 0.015268062241375446\n",
      "70 0.010911641642451286\n",
      "80 0.013616204261779785\n",
      "90 0.004029718227684498\n",
      "100 0.0023262561298906803\n",
      "110 0.10054083913564682\n",
      "120 0.005719964858144522\n",
      "130 0.0018067894270643592\n",
      "140 0.0011895529460161924\n",
      "150 0.10145141184329987\n",
      "160 0.007229849696159363\n",
      "170 0.0013624539133161306\n",
      "180 0.0008759834454394877\n",
      "190 0.000573917175643146\n"
     ]
    }
   ],
   "source": [
    "loss_func = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=1e-2)\n",
    "\n",
    "model.train()\n",
    "for epoch in range(200):\n",
    "    for i, data in enumerate(dataloader):\n",
    "        x, y = data\n",
    "\n",
    "        optimizer.zero_grad()\n",
    "\n",
    "        #计算输出\n",
    "        y_pred = model(x, y)\n",
    "\n",
    "        #丢弃y的第一个词\n",
    "        #因为训练的时候是以y的每一个词输入,预测下一个词\n",
    "        #所以在计算loss的时候不需要第一个词\n",
    "        #[b,11] -> [b,10]\n",
    "        y = y[:, 1:]\n",
    "\n",
    "        #打平,不然计算不了loss\n",
    "        #[b,10,27] -> [b*10,27]\n",
    "        y_pred = y_pred.reshape(-1, 27)\n",
    "\n",
    "        #[b,10] -> [b*10]\n",
    "        y = y.reshape(-1)\n",
    "\n",
    "        loss = loss_func(y_pred, y)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "\n",
    "    if epoch % 10 == 0:\n",
    "        print(epoch, loss.item())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "06874eb1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('03-12-17', '<SOS>17/Dec/2003<EOS>')"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#构造反转的字典\n",
    "reverse_zidian = {}\n",
    "for k, v in zidian.items():\n",
    "    reverse_zidian[v] = k\n",
    "reverse_zidian\n",
    "\n",
    "\n",
    "#数字化的句子转字符串\n",
    "def seq_to_str(seq):\n",
    "    seq = seq.detach().numpy()\n",
    "    return ''.join([reverse_zidian[idx] for idx in seq])\n",
    "\n",
    "\n",
    "seq_to_str(sample[0][0]), seq_to_str(sample[1][0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "af32f9b3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "82-10-13 <SOS>13/Oct/1982<EOS> 13/Oct/1982\n",
      "30-01-06 <SOS>06/Jan/2030<EOS> 06/Jan/2030\n",
      "77-02-21 <SOS>21/Feb/1977<EOS> 21/Feb/1977\n",
      "18-09-03 <SOS>03/Sep/2018<EOS> 03/Sep/2018\n",
      "85-11-12 <SOS>12/Nov/1985<EOS> 12/Nov/1985\n",
      "79-05-02 <SOS>02/May/1979<EOS> 02/May/1979\n",
      "86-11-19 <SOS>19/Nov/1986<EOS> 19/Nov/1986\n",
      "23-12-11 <SOS>11/Dec/2023<EOS> 11/Dec/2023\n",
      "80-05-08 <SOS>08/May/1980<EOS> 08/May/1980\n",
      "27-02-16 <SOS>16/Feb/2027<EOS> 16/Feb/2027\n",
      "92-09-16 <SOS>16/Sep/1992<EOS> 16/Sep/1992\n",
      "21-10-14 <SOS>14/Oct/2021<EOS> 14/Oct/2021\n",
      "95-11-05 <SOS>05/Nov/1995<EOS> 05/Nov/1995\n",
      "86-10-07 <SOS>07/Oct/1986<EOS> 07/Oct/1986\n",
      "88-02-28 <SOS>28/Feb/1988<EOS> 28/Feb/1988\n",
      "34-02-14 <SOS>14/Feb/2034<EOS> 14/Feb/2034\n",
      "81-03-10 <SOS>10/Mar/1981<EOS> 10/Mar/1981\n",
      "92-10-23 <SOS>23/Oct/1992<EOS> 23/Oct/1992\n",
      "34-07-06 <SOS>06/Jul/2034<EOS> 06/Jul/2034\n",
      "04-03-13 <SOS>13/Mar/2004<EOS> 13/Mar/2004\n",
      "26-02-04 <SOS>04/Feb/2026<EOS> 04/Feb/2026\n",
      "93-06-02 <SOS>02/Jun/1993<EOS> 02/Jun/1993\n",
      "18-09-25 <SOS>25/Sep/2018<EOS> 25/Sep/2018\n",
      "01-06-26 <SOS>26/Jun/2001<EOS> 26/Jun/2001\n",
      "91-03-14 <SOS>14/Mar/1991<EOS> 14/Mar/1991\n",
      "17-12-02 <SOS>02/Dec/2017<EOS> 02/Dec/2017\n",
      "03-03-29 <SOS>29/Mar/2003<EOS> 29/Mar/2003\n",
      "22-09-14 <SOS>14/Sep/2022<EOS> 14/Sep/2022\n",
      "82-01-01 <SOS>01/Jan/1982<EOS> 01/Jan/1982\n",
      "16-04-13 <SOS>13/Apr/2016<EOS> 13/Apr/2016\n",
      "78-11-09 <SOS>09/Nov/1978<EOS> 09/Nov/1978\n",
      "03-05-09 <SOS>09/May/2003<EOS> 09/May/2003\n",
      "27-11-19 <SOS>19/Nov/2027<EOS> 19/Nov/2027\n",
      "24-12-04 <SOS>04/Dec/2024<EOS> 04/Dec/2024\n",
      "90-11-24 <SOS>24/Nov/1990<EOS> 24/Nov/1990\n",
      "79-07-15 <SOS>15/Jul/1979<EOS> 15/Jul/1979\n",
      "11-10-05 <SOS>05/Oct/2011<EOS> 05/Oct/2011\n",
      "93-12-07 <SOS>07/Dec/1993<EOS> 07/Dec/1993\n",
      "10-12-15 <SOS>15/Dec/2010<EOS> 15/Dec/2010\n",
      "83-01-12 <SOS>12/Jan/1983<EOS> 12/Jan/1983\n",
      "76-12-09 <SOS>09/Dec/1976<EOS> 09/Dec/1976\n",
      "12-11-19 <SOS>19/Nov/2012<EOS> 19/Nov/2012\n",
      "03-07-25 <SOS>25/Jul/2003<EOS> 25/Jul/2003\n",
      "01-04-22 <SOS>22/Apr/2001<EOS> 22/Apr/2001\n",
      "25-11-19 <SOS>19/Nov/2025<EOS> 19/Nov/2025\n",
      "77-03-29 <SOS>29/Mar/1977<EOS> 29/Mar/1977\n",
      "80-07-31 <SOS>31/Jul/1980<EOS> 31/Jul/1980\n",
      "07-11-17 <SOS>17/Nov/2007<EOS> 17/Nov/2007\n",
      "14-09-09 <SOS>09/Sep/2014<EOS> 09/Sep/2014\n",
      "23-07-09 <SOS>09/Jul/2023<EOS> 09/Jul/2023\n",
      "75-09-15 <SOS>15/Sep/1975<EOS> 15/Sep/1975\n",
      "84-12-26 <SOS>26/Dec/1984<EOS> 26/Dec/1984\n",
      "28-02-08 <SOS>08/Feb/2028<EOS> 08/Feb/2028\n",
      "97-08-07 <SOS>07/Aug/1997<EOS> 07/Aug/1997\n",
      "25-07-07 <SOS>07/Jul/2025<EOS> 07/Jul/2025\n",
      "03-12-10 <SOS>10/Dec/2003<EOS> 10/Dec/2003\n",
      "30-09-02 <SOS>02/Sep/2030<EOS> 02/Sep/2030\n",
      "94-01-15 <SOS>15/Jan/1994<EOS> 15/Jan/1994\n",
      "84-06-20 <SOS>20/Jun/1984<EOS> 20/Jun/1984\n",
      "22-06-16 <SOS>16/Jun/2022<EOS> 16/Jun/2022\n",
      "25-09-05 <SOS>05/Sep/2025<EOS> 05/Sep/2025\n",
      "97-04-07 <SOS>07/Apr/1997<EOS> 07/Apr/1997\n",
      "11-12-14 <SOS>14/Dec/2011<EOS> 14/Dec/2011\n",
      "94-01-03 <SOS>03/Jan/1994<EOS> 03/Jan/1994\n",
      "86-08-11 <SOS>11/Aug/1986<EOS> 11/Aug/1986\n",
      "23-02-09 <SOS>09/Feb/2023<EOS> 09/Feb/2023\n",
      "07-12-31 <SOS>31/Dec/2007<EOS> 31/Dec/2007\n",
      "75-08-16 <SOS>16/Aug/1975<EOS> 16/Aug/1975\n",
      "80-01-04 <SOS>04/Jan/1980<EOS> 04/Jan/1980\n",
      "85-03-24 <SOS>24/Mar/1985<EOS> 24/Mar/1985\n",
      "28-11-03 <SOS>03/Nov/2028<EOS> 03/Nov/2028\n",
      "99-02-05 <SOS>05/Feb/1999<EOS> 05/Feb/1999\n",
      "34-03-21 <SOS>21/Mar/2034<EOS> 21/Mar/2034\n",
      "17-10-23 <SOS>23/Oct/2017<EOS> 23/Oct/2017\n",
      "15-12-09 <SOS>09/Dec/2015<EOS> 09/Dec/2015\n",
      "92-01-13 <SOS>13/Jan/1992<EOS> 13/Jan/1992\n",
      "23-02-20 <SOS>20/Feb/2023<EOS> 20/Feb/2023\n",
      "29-09-04 <SOS>04/Sep/2029<EOS> 04/Sep/2029\n",
      "97-01-18 <SOS>18/Jan/1997<EOS> 18/Jan/1997\n",
      "10-03-08 <SOS>08/Mar/2010<EOS> 08/Mar/2010\n",
      "12-12-09 <SOS>09/Dec/2012<EOS> 09/Dec/2012\n",
      "97-01-25 <SOS>25/Jan/1997<EOS> 25/Jan/1997\n",
      "29-02-07 <SOS>07/Feb/2029<EOS> 07/Feb/2029\n",
      "11-06-11 <SOS>11/Jun/2011<EOS> 11/Jun/2011\n",
      "77-10-10 <SOS>10/Oct/1977<EOS> 10/Oct/1977\n",
      "27-04-23 <SOS>23/Apr/2027<EOS> 23/Apr/2027\n",
      "06-06-01 <SOS>01/Jun/2006<EOS> 01/Jun/2006\n",
      "85-08-27 <SOS>27/Aug/1985<EOS> 27/Aug/1985\n",
      "34-07-01 <SOS>01/Jul/2034<EOS> 01/Jul/2034\n",
      "89-10-27 <SOS>27/Oct/1989<EOS> 27/Oct/1989\n",
      "75-07-03 <SOS>03/Jul/1975<EOS> 03/Jul/1975\n",
      "19-08-20 <SOS>20/Aug/2019<EOS> 20/Aug/2019\n",
      "85-11-27 <SOS>27/Nov/1985<EOS> 27/Nov/1985\n",
      "94-09-17 <SOS>17/Sep/1994<EOS> 17/Sep/1994\n",
      "34-05-12 <SOS>12/May/2034<EOS> 12/May/2034\n",
      "79-02-02 <SOS>02/Feb/1979<EOS> 02/Feb/1979\n",
      "75-08-08 <SOS>08/Aug/1975<EOS> 08/Aug/1975\n",
      "75-12-14 <SOS>14/Dec/1975<EOS> 14/Dec/1975\n",
      "82-10-27 <SOS>27/Oct/1982<EOS> 27/Oct/1982\n",
      "14-11-09 <SOS>09/Nov/2014<EOS> 09/Nov/2014\n"
     ]
    }
   ],
   "source": [
    "#预测\n",
    "def predict(x):\n",
    "    model.eval()\n",
    "\n",
    "    #编码层\n",
    "    h, c = model.encode(x)\n",
    "\n",
    "    #初始化输入,每一个词的输入应该是上一个词的输出\n",
    "    #因为我们的y第一个词固定是<SOS>,所以直接以这个词开始\n",
    "    #[b]\n",
    "    out = torch.full((x.size(0), ), zidian['<SOS>'], dtype=torch.int64)\n",
    "    #[b] -> [b,16]\n",
    "    out = model.decoder_embed(out)\n",
    "\n",
    "    #循环生成9个词,收尾的两个标签没有预测的价值,直接忽略了\n",
    "    outs = []\n",
    "    for i in range(9):\n",
    "\n",
    "        #把每个词输入循环网络\n",
    "        #第一个词的记忆是x的最后一个词的记忆\n",
    "        #往后每个词的记忆是上一个词的记忆\n",
    "        #[b,16] -> [b,32],[b,32]\n",
    "        h, c = model.decoder_cell(out, (h, c))\n",
    "\n",
    "        #[b,32] -> [b,27]\n",
    "        out = model.out_fc(h)\n",
    "\n",
    "        #把每一步的记忆输出成词\n",
    "        #[b,27] -> [b]\n",
    "        out = out.argmax(dim=1)\n",
    "        outs.append(out)\n",
    "\n",
    "        #把这一步的输出作为下一步的输入\n",
    "        #[b] -> [b,16]\n",
    "        out = model.decoder_embed(out)\n",
    "\n",
    "    #把所有的输出词组合成一句话\n",
    "    #[9,b]\n",
    "    outs = torch.stack(outs, dim=0)\n",
    "    #[9,b] -> [b,9]\n",
    "    outs = outs.permute(1, 0)\n",
    "\n",
    "    return outs\n",
    "\n",
    "\n",
    "#测试\n",
    "for i, data in enumerate(dataloader):\n",
    "    x, y = data\n",
    "    y_pred = predict(x)\n",
    "    for xi, yi, pi in zip(x, y, y_pred):\n",
    "        print(seq_to_str(xi), seq_to_str(yi), seq_to_str(pi))\n",
    "    break"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
